package ca.etsmtl.log540.tp3;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.util.concurrent.CountDownLatch;
import java.util.logging.Level;
import java.util.logging.Logger;

public class UTFServerNIO2 {

    private Selector selector = null;
    private AsynchronousServerSocketChannel serverChannel;
    private InetSocketAddress address = null;
    private int PORT = 1337;

    public static void main(String[] args) {
        new UTFServerNIO2().run();
    }

    void run() {
        try {
            serverChannel = AsynchronousServerSocketChannel.open();
            address = new InetSocketAddress(PORT);
            serverChannel.bind(address);
            final CountDownLatch latch = new CountDownLatch(1);

            serverChannel.accept(null, new AcceptCompletionHandler(serverChannel));

            System.out.println("Server listening on port " + PORT);
            
            try {
                latch.await();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        } catch (IOException ex) {
            Logger.getLogger(UTFServerNIO2.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    static class AcceptCompletionHandler implements
            CompletionHandler<AsynchronousSocketChannel, ByteBuffer> {

        private final AsynchronousServerSocketChannel serverChannel;

        public AcceptCompletionHandler(AsynchronousServerSocketChannel channel) {
            this.serverChannel = channel;
        }

        @Override
        public void completed(AsynchronousSocketChannel result,
                ByteBuffer attachment) {
            try {
                serverChannel.accept(null, this);
                ByteBuffer buffer = ByteBuffer.allocate(100);
                result.read(buffer, buffer, new ReadCompletionHandler(result));

            } catch (Throwable exc) {
                failed(exc, attachment);
            }

        }

        @Override
        public void failed(Throwable exc, ByteBuffer attachment) {
            // TODO Exercice #3

        }

    }

    static class ReadCompletionHandler implements
            CompletionHandler<Integer, ByteBuffer> {

        private final AsynchronousSocketChannel channel;

        public ReadCompletionHandler(AsynchronousSocketChannel channel) {
            this.channel = channel;
        }

        @Override
        public void completed(Integer result, ByteBuffer attachment) {

            if (result != -1) {
                //…
                byte[] buffer = new byte[result];
                attachment.rewind();
                // Rewind the input buffer to read from the beginning

                attachment.get(buffer);
                String message = new String(buffer);

                System.out.println("Received message from client : "
                        + message);
                channel.read(attachment, attachment, this);
            }
        }

        @Override
        public void failed(Throwable exc, ByteBuffer attachment) {
            // TODO Exercice #3

        }

    }
}
